/*************************************************
filename	: graphics_interface.h
author		: Stefan lulham
desc		: Contains the graphics interface base
*************************************************/
#ifndef D_GRAPHICS_INTERFACE_H
#define D_GRAPHICS_INTERFACE_H

#include <list>
#include <stack>
#include <algorithm>

#include <modules\interface.h>
#include <platform.h>

#include <modules\system\system_gadget.h>
#include <modules\graphics\color.h>
#include <modules\graphics\vertex.h>
#include <modules\graphics\indexed_triangle.h>
#include <modules\graphics\mesh.h>
#include <modules\graphics\sprite.h>
#include <modules\graphics\texture.h>
#include <modules\graphics\camera.h>
#include <modules\graphics\font.h>
#include <modules\graphics\model.h>
#include <modules\graphics\entity_pose.h>
#include <modules\graphics\static_entity.h>
#include <modules\graphics\animated_entity.h>
#include <modules\graphics\graphics_context.h>
#include <modules\graphics\graphics_enums.h>

using namespace DelGE::Modules::System;
using namespace std;

namespace DelGE
{
	namespace Modules
	{
		namespace Graphics
		{
			class GraphicsInterface : public Interface
			{
			protected:
				list<GraphicsContext*> lContexts;					// A list of all contexts
				GraphicsContext* pCurrentContext;					// The current context to draw to
				DelGEGraphicsBlendMode eBlendMode;					// The current IM blend mode.

				Texture* pCurrentRenderBuffer;						// This is a texture to which we will render.

				Color oGlobalColor;
				Color oClearColor;

				Matrix oModelViewMatrix;
				Matrix oProjectionMatrix;
				stack<Matrix> lMatrixStack;

			public:
				GraphicsInterface();
				virtual ~GraphicsInterface();

				// Context methods
				void AddContext(GraphicsContext* pContext);
				void RemoveContext(GraphicsContext* pContext);
				void SetCurrentContext(GraphicsContext* pContext);
				GraphicsContext *GetCurrentContext();
				void DestroyAllContexts();
				virtual GraphicsContext* CreateContext(SystemGadget* pGadget) = 0;
				// Create contexts from platform handles
				#if defined(DELGE_PLATFORM_WIN32)
				virtual GraphicsContext* CreateContext(HWND hWnd) = 0;
				#endif

				virtual void Setup2DProjection(int iWidth = -1, int iHeight = -1) = 0;
				virtual void SetViewport(int iX, int iY, int iWidth, int iHeight) = 0;

				virtual void SetClearColor(int iRed, int iGreen, int iBlue, int iAlpha = 255) = 0;
				virtual void SetClearColor(const Color& rColor) = 0;
				int GetClearColor_Red();
				int GetClearColor_Green();
				int GetClearColor_Blue();
				int GetClearColor_Alpha();
				Color GetClearColor();

				virtual void SetGlobalColor(int iRed, int iGreen, int iBlue, int iAlpha = 255) = 0;
				virtual void SetGlobalColor(const Color& rColor) = 0;
				int GetGlobalColor_Red();
				int GetGlobalColor_Green();
				int GetGlobalColor_Blue();
				int GetGlobalColor_Alpha();
				Color GetGlobalColor();

				virtual void ClearScreen() = 0;
				virtual void Flip() = 0;
				virtual void SetVsync(bool bVsync) = 0;

				virtual void SetBlendMode(DelGEGraphicsBlendMode eBlendMode) = 0;
				DelGEGraphicsBlendMode GetBlendMode();

				virtual Texture* LoadTexture(string sFilepath, 
													const Color& oMaskColor = DELGE_GRAPHICSCOLOR_NONE, 
													GraphicsTexture_UVWrapMode eUWrapMode = GraphicsTexture_UVWrapMode_Clamp,
													GraphicsTexture_UVWrapMode eVWrapMode = GraphicsTexture_UVWrapMode_Clamp) = 0;
				virtual Texture* CreateTexture(int iWidth, int iHeight,
											   GraphicsTexture_UVWrapMode eUWrapMode = GraphicsTexture_UVWrapMode_Clamp,
											   GraphicsTexture_UVWrapMode eVWrapMode = GraphicsTexture_UVWrapMode_Clamp) = 0;

				virtual Font* LoadFont(string sFilepath, int iSize) = 0;
				virtual void UnloadFont(Font* pFont) = 0;

				virtual void BeginRenderToTexture(Texture* pGraphicsTexture) = 0;
				virtual void EndRenderToTexture() = 0;

				virtual void DrawRect(float fX, float fY, float fWidth, float fHeight) = 0;
				virtual void DrawLine(float fX0, float fY0, float fX1, float fY1) = 0;

				virtual void DrawTexture(Texture* pTexture, float fX, float fY, float fWidth = -1, float fHeight = -1) = 0;
				virtual void DrawTextureArea(Texture* pTexture, float fX, float fY, float fWidth = -1, float fHeight = -1,
											 int iAreaX = -1, int iAreaY = -1, int iAreaWidth = -1, int iAreaHeight = -1) = 0;
				virtual void DrawMesh(Mesh* pMesh, bool bAutoBuild = true) = 0;
				virtual void DrawModel(Model* pModel) = 0;
				virtual void DrawEntity(Entity* pEntity) = 0;
				virtual void DrawCamera(Camera* pCamera) = 0;
				virtual void DrawSprite(Sprite* pSprite) = 0;
				virtual void DrawText(string sText, float fX, float fY, Font* pFont) = 0;

				virtual float TextWidth(string sText, Font* pFont) = 0;
				virtual float TextHeight(string sText, Font* pFont) = 0;

				virtual void BindTexture(Texture* pTexture) = 0;

				virtual void SetModelViewMatrix(const Matrix& rMatrix) = 0;
				virtual void SetProjectionMatrix(const Matrix& rMatrix) = 0;
				Matrix GetModelViewMatrix();
				Matrix GetProjectionMatrix();

				void PushWorldMatrix();
				void PopWorldMatrix();

				virtual void Begin2DRendering() = 0;
				virtual void Begin3DRendering() = 0;

				virtual void EnableWireframeMode() = 0;
				virtual void EnableDepthTesting() = 0;
				virtual void DisableWireframeMode() = 0;
				virtual void DisableDepthTesting() = 0;

				virtual void EnableLighting() = 0;
				virtual void DisableLighting() = 0;
			};
		}
	}
}

#endif